/*
 * RegistroDiarioNode.c
 *
 *  Created on: 04/07/2011
 *      Author: Hyzandey
 */

#include "RegistroDiarioNode.h"

RegistroDiarioNode *criaRegistroDiarioNode(RegistroDiario *registro) {
	RegistroDiarioNode *registroNode = NULL;

	if (registro) {
		registroNode = (RegistroDiarioNode*) malloc(sizeof(RegistroDiarioNode));
		registroNode->registro = registro;
		registroNode->direita = NULL;
		registroNode->esquerda = NULL;
	}

	return registroNode;
}

int insereRegistroDiarioNode(RegistroDiarioNode *raizNode,
		RegistroDiarioNode *novoNode) {
	if (novoNode && raizNode) {
		int comparacao = comparaRegistroDiario(raizNode->registro,
				novoNode->registro);
		if (comparacao != COMPARACAO_REGISTRO_DIARIO_FALHA) {
			if (comparacao > 0) {
				if (!raizNode->direita) {
					raizNode->direita = novoNode;
					return EXIT_SUCCESS;
				} else {
					return insereRegistroDiarioNode(raizNode->direita, novoNode);
				}
			} else {
				if (!raizNode->esquerda) {
					raizNode->esquerda = novoNode;
					return EXIT_SUCCESS;
				} else {
					return insereRegistroDiarioNode(raizNode->esquerda,
							novoNode);
				}
			}
		}
	}
	return EXIT_FAILURE;
}

int insereRegistroDiario(RegistroDiarioNode **raizNode,
		RegistroDiario *novoRegistro) {
	if (novoRegistro) {
		RegistroDiarioNode *novoNode = criaRegistroDiarioNode(novoRegistro);
		if (*raizNode) {
			return insereRegistroDiarioNode(*raizNode, novoNode);
		} else {
			*raizNode = novoNode;
			return EXIT_SUCCESS;
		}
	}
	return EXIT_FAILURE;
}

void transformaRegistroDiarioNodeHeap(RegistroDiarioNode *raizNode) {
	if (raizNode) {

		transformaRegistroDiarioNodeHeap(raizNode->direita);
		transformaRegistroDiarioNodeHeap(raizNode->esquerda);

		int comparacao = comparaRegistroDiario(raizNode->registro,
				raizNode->esquerda->registro);

		if (comparacao > 0) {
			RegistroDiario *temp = raizNode->registro;
			raizNode->registro = raizNode->esquerda->registro;
			raizNode->esquerda->registro = temp;
		}

		comparacao = comparaRegistroDiario(raizNode->registro,
				raizNode->direita->registro);

		if (comparacao > 0) {
			RegistroDiario *temp = raizNode->registro;
			raizNode->registro = raizNode->direita->registro;
			raizNode->direita->registro = temp;
		}

	}
}

RegistroDiarioNode *retiraMaiorNode(RegistroDiarioNode **heap) {

	RegistroDiarioNode *raiz = *heap;

	if (raiz->direita && raiz->esquerda) {

		int maior = comparaRegistroDiario(raiz->direita->registro,
				raiz->esquerda->registro);

		if (maior > 0) {
			if (raiz->direita->direita || raiz->direita->esquerda) {
				return retiraMaiorNode(&raiz->direita);
			} else {
				RegistroDiarioNode *temp = raiz->direita;
				raiz->direita = NULL;
				return temp;
			}
		} else {
			if (raiz->esquerda->direita || raiz->esquerda->esquerda) {
				return retiraMaiorNode(&raiz->esquerda);
			} else {
				RegistroDiarioNode *temp = raiz->esquerda;
				raiz->esquerda = NULL;
				return temp;
			}
		}

	} else if (raiz->direita) {
		if (raiz->direita->direita || raiz->direita->esquerda) {
			return retiraMaiorNode(&raiz->direita);
		} else {
			RegistroDiarioNode *temp = raiz->direita;
			raiz->direita = NULL;
			return temp;
		}
	} else if (raiz->esquerda) {
		if (raiz->esquerda->direita || raiz->esquerda->esquerda) {
			return retiraMaiorNode(&raiz->esquerda);
		} else {
			RegistroDiarioNode *temp = raiz->esquerda;
			raiz->esquerda = NULL;
			return temp;
		}
	} else {
		RegistroDiarioNode *temp = *heap;

		*heap = NULL;

		return temp;
	}

	return NULL;
}

RegistroDiario *retiraMenorRegistroDiario(RegistroDiarioNode **heap) {

	RegistroDiarioNode *raiz = *heap;

	transformaRegistroDiarioNodeHeap(raiz);

	RegistroDiarioNode *maior = retiraMaiorNode(heap);

	if (!maior) {
		return NULL;
	}

	maior->direita = NULL;
	maior->esquerda = NULL;

	int sucesso = insereRegistroDiarioNode(maior, raiz->esquerda);

	if (sucesso == EXIT_FAILURE) {
		return NULL;
	}

	sucesso = insereRegistroDiarioNode(maior, raiz->direita);

	if (sucesso == EXIT_FAILURE) {
		return NULL;
	}

	RegistroDiario *menorRegistro = raiz->registro;

	liberaPonteiro(raiz);

	*heap = maior;

	return menorRegistro;

}

RegistroDiarioNode *retiraRaiz(RegistroDiarioNode **heap) {

	RegistroDiarioNode *novaRaiz = (*heap)->direita;
	RegistroDiarioNode *outroNode = (*heap)->esquerda;

	int maiorNode = comparaRegistroDiario((*heap)->direita->registro,
			(*heap)->esquerda->registro);

	if (maiorNode == COMPARACAO_REGISTRO_DIARIO_FALHA) {
		return NULL;
	}

	if (maiorNode > 0) {
		novaRaiz = (*heap)->esquerda;
		outroNode = (*heap)->direita;
	}

	int sucesso = insereRegistroDiarioNode(novaRaiz, outroNode);

	if (sucesso == EXIT_SUCCESS) {
		return NULL;
	}

	return NULL;

}

void limpaArvore(RegistroDiarioNode *arvore) {
	if (arvore) {
		limpaArvore(arvore->direita);
		limpaArvore(arvore->esquerda);

		liberaPonteiro(arvore->registro);

		liberaPonteiro(arvore);
	}
}

